// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

#include <DatabaseCorrelation.h>
#include <DataNode.h>
#include <algorithm>
#include <map>

//
// Enum conversion methods for DatabaseCorrelation::CorrelationMethod
//

static const char *CorrelationMethod_strings[] = {
"IndexForIndexCorrelation", "StretchedIndexCorrelation", "TimeCorrelation",
"CycleCorrelation", "UserDefinedCorrelation"};

std::string
DatabaseCorrelation::CorrelationMethod_ToString(DatabaseCorrelation::CorrelationMethod t)
{
    int index = int(t);
    if(index < 0 || index >= 5) index = 0;
    return CorrelationMethod_strings[index];
}

std::string
DatabaseCorrelation::CorrelationMethod_ToString(int t)
{
    int index = (t < 0 || t >= 5) ? 0 : t;
    return CorrelationMethod_strings[index];
}

bool
DatabaseCorrelation::CorrelationMethod_FromString(const std::string &s, DatabaseCorrelation::CorrelationMethod &val)
{
    val = DatabaseCorrelation::IndexForIndexCorrelation;
    for(int i = 0; i < 5; ++i)
    {
        if(s == CorrelationMethod_strings[i])
        {
            val = (CorrelationMethod)i;
            return true;
        }
    }
    return false;
}

// ****************************************************************************
// Method: DatabaseCorrelation::DatabaseCorrelation
//
// Purpose:
//   Init utility for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void DatabaseCorrelation::Init()
{
    numStates = 1;
    method = IndexForIndexCorrelation;

    DatabaseCorrelation::SelectAll();
}

// ****************************************************************************
// Method: DatabaseCorrelation::DatabaseCorrelation
//
// Purpose:
//   Copy utility for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void DatabaseCorrelation::Copy(const DatabaseCorrelation &obj)
{
    name = obj.name;
    numStates = obj.numStates;
    method = obj.method;
    databaseNames = obj.databaseNames;
    databaseNStates = obj.databaseNStates;
    databaseTimes = obj.databaseTimes;
    databaseCycles = obj.databaseCycles;
    indices = obj.indices;
    condensedTimes = obj.condensedTimes;
    condensedCycles = obj.condensedCycles;

    DatabaseCorrelation::SelectAll();
}

// Type map format string
const char *DatabaseCorrelation::TypeMapFormatString = DATABASECORRELATION_TMFS;
const AttributeGroup::private_tmfs_t DatabaseCorrelation::TmfsStruct = {DATABASECORRELATION_TMFS};


// ****************************************************************************
// Method: DatabaseCorrelation::DatabaseCorrelation
//
// Purpose:
//   Default constructor for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DatabaseCorrelation::DatabaseCorrelation() :
    AttributeSubject(DatabaseCorrelation::TypeMapFormatString)
{
    DatabaseCorrelation::Init();
}

// ****************************************************************************
// Method: DatabaseCorrelation::DatabaseCorrelation
//
// Purpose:
//   Constructor for the derived classes of DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DatabaseCorrelation::DatabaseCorrelation(private_tmfs_t tmfs) :
    AttributeSubject(tmfs.tmfs)
{
    DatabaseCorrelation::Init();
}

// ****************************************************************************
// Method: DatabaseCorrelation::DatabaseCorrelation
//
// Purpose:
//   Copy constructor for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DatabaseCorrelation::DatabaseCorrelation(const DatabaseCorrelation &obj) :
    AttributeSubject(DatabaseCorrelation::TypeMapFormatString)
{
    DatabaseCorrelation::Copy(obj);
}

// ****************************************************************************
// Method: DatabaseCorrelation::DatabaseCorrelation
//
// Purpose:
//   Copy constructor for derived classes of the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DatabaseCorrelation::DatabaseCorrelation(const DatabaseCorrelation &obj, private_tmfs_t tmfs) :
    AttributeSubject(tmfs.tmfs)
{
    DatabaseCorrelation::Copy(obj);
}

// ****************************************************************************
// Method: DatabaseCorrelation::~DatabaseCorrelation
//
// Purpose:
//   Destructor for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DatabaseCorrelation::~DatabaseCorrelation()
{
    // nothing here
}

// ****************************************************************************
// Method: DatabaseCorrelation::operator =
//
// Purpose:
//   Assignment operator for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DatabaseCorrelation&
DatabaseCorrelation::operator = (const DatabaseCorrelation &obj)
{
    if (this == &obj) return *this;

    DatabaseCorrelation::Copy(obj);

    return *this;
}

// ****************************************************************************
// Method: DatabaseCorrelation::operator ==
//
// Purpose:
//   Comparison operator == for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::operator == (const DatabaseCorrelation &obj) const
{
    // Create the return value
    return ((name == obj.name) &&
            (numStates == obj.numStates) &&
            (method == obj.method) &&
            (databaseNames == obj.databaseNames) &&
            (databaseNStates == obj.databaseNStates) &&
            (databaseTimes == obj.databaseTimes) &&
            (databaseCycles == obj.databaseCycles) &&
            (indices == obj.indices) &&
            (condensedTimes == obj.condensedTimes) &&
            (condensedCycles == obj.condensedCycles));
}

// ****************************************************************************
// Method: DatabaseCorrelation::operator !=
//
// Purpose:
//   Comparison operator != for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::operator != (const DatabaseCorrelation &obj) const
{
    return !(this->operator == (obj));
}

// ****************************************************************************
// Method: DatabaseCorrelation::TypeName
//
// Purpose:
//   Type name method for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const std::string
DatabaseCorrelation::TypeName() const
{
    return "DatabaseCorrelation";
}

// ****************************************************************************
// Method: DatabaseCorrelation::CopyAttributes
//
// Purpose:
//   CopyAttributes method for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::CopyAttributes(const AttributeGroup *atts)
{
    if(TypeName() != atts->TypeName())
        return false;

    // Call assignment operator.
    const DatabaseCorrelation *tmp = (const DatabaseCorrelation *)atts;
    *this = *tmp;

    return true;
}

// ****************************************************************************
// Method: DatabaseCorrelation::CreateCompatible
//
// Purpose:
//   CreateCompatible method for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
DatabaseCorrelation::CreateCompatible(const std::string &tname) const
{
    AttributeSubject *retval = 0;
    if(TypeName() == tname)
        retval = new DatabaseCorrelation(*this);
    // Other cases could go here too.

    return retval;
}

// ****************************************************************************
// Method: DatabaseCorrelation::NewInstance
//
// Purpose:
//   NewInstance method for the DatabaseCorrelation class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
DatabaseCorrelation::NewInstance(bool copy) const
{
    AttributeSubject *retval = 0;
    if(copy)
        retval = new DatabaseCorrelation(*this);
    else
        retval = new DatabaseCorrelation;

    return retval;
}

// ****************************************************************************
// Method: DatabaseCorrelation::SelectAll
//
// Purpose:
//   Selects all attributes.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
DatabaseCorrelation::SelectAll()
{
    Select(ID_name,            (void *)&name);
    Select(ID_numStates,       (void *)&numStates);
    Select(ID_method,          (void *)&method);
    Select(ID_databaseNames,   (void *)&databaseNames);
    Select(ID_databaseNStates, (void *)&databaseNStates);
    Select(ID_databaseTimes,   (void *)&databaseTimes);
    Select(ID_databaseCycles,  (void *)&databaseCycles);
    Select(ID_indices,         (void *)&indices);
    Select(ID_condensedTimes,  (void *)&condensedTimes);
    Select(ID_condensedCycles, (void *)&condensedCycles);
}

///////////////////////////////////////////////////////////////////////////////
// Persistence methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: DatabaseCorrelation::CreateNode
//
// Purpose:
//   This method creates a DataNode representation of the object so it can be saved to a config file.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::CreateNode(DataNode *parentNode, bool completeSave, bool forceAdd)
{
    if(parentNode == 0)
        return false;

    DatabaseCorrelation defaultObject;
    bool addToParent = false;
    // Create a node for DatabaseCorrelation.
    DataNode *node = new DataNode("DatabaseCorrelation");

    if(completeSave || !FieldsEqual(ID_name, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("name", name));
    }

    if(completeSave || !FieldsEqual(ID_numStates, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("numStates", numStates));
    }

    if(completeSave || !FieldsEqual(ID_method, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("method", CorrelationMethod_ToString(method)));
    }

    if(completeSave || !FieldsEqual(ID_databaseNames, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("databaseNames", databaseNames));
    }

    if(completeSave || !FieldsEqual(ID_databaseNStates, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("databaseNStates", databaseNStates));
    }

    if(completeSave || !FieldsEqual(ID_databaseTimes, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("databaseTimes", databaseTimes));
    }

    if(completeSave || !FieldsEqual(ID_databaseCycles, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("databaseCycles", databaseCycles));
    }

    if(completeSave || !FieldsEqual(ID_indices, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("indices", indices));
    }

    if(completeSave || !FieldsEqual(ID_condensedTimes, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("condensedTimes", condensedTimes));
    }

    if(completeSave || !FieldsEqual(ID_condensedCycles, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("condensedCycles", condensedCycles));
    }


    // Add the node to the parent node.
    if(addToParent || forceAdd)
        parentNode->AddNode(node);
    else
        delete node;

    return (addToParent || forceAdd);
}

// ****************************************************************************
// Method: DatabaseCorrelation::SetFromNode
//
// Purpose:
//   This method sets attributes in this object from values in a DataNode representation of the object.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
DatabaseCorrelation::SetFromNode(DataNode *parentNode)
{
    if(parentNode == 0)
        return;

    DataNode *searchNode = parentNode->GetNode("DatabaseCorrelation");
    if(searchNode == 0)
        return;

    DataNode *node;
    if((node = searchNode->GetNode("name")) != 0)
        SetName(node->AsString());
    if((node = searchNode->GetNode("numStates")) != 0)
        SetNumStates(node->AsInt());
    if((node = searchNode->GetNode("method")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 5)
                SetMethod(CorrelationMethod(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            CorrelationMethod value;
            if(CorrelationMethod_FromString(node->AsString(), value))
                SetMethod(value);
        }
    }
    if((node = searchNode->GetNode("databaseNames")) != 0)
        SetDatabaseNames(node->AsStringVector());
    if((node = searchNode->GetNode("databaseNStates")) != 0)
        SetDatabaseNStates(node->AsIntVector());
    if((node = searchNode->GetNode("databaseTimes")) != 0)
        SetDatabaseTimes(node->AsDoubleVector());
    if((node = searchNode->GetNode("databaseCycles")) != 0)
        SetDatabaseCycles(node->AsIntVector());
    if((node = searchNode->GetNode("indices")) != 0)
        SetIndices(node->AsIntVector());
    if((node = searchNode->GetNode("condensedTimes")) != 0)
        SetCondensedTimes(node->AsDoubleVector());
    if((node = searchNode->GetNode("condensedCycles")) != 0)
        SetCondensedCycles(node->AsIntVector());
}

///////////////////////////////////////////////////////////////////////////////
// Set property methods
///////////////////////////////////////////////////////////////////////////////

void
DatabaseCorrelation::SetName(const std::string &name_)
{
    name = name_;
    Select(ID_name, (void *)&name);
}

// ****************************************************************************
// Method: DatabaseCorrelation::SetNumStates
//
// Purpose:
//    Sets the number of states in the correlation and adjusts the correlation
//    indices.
//
// Arguments:
//   nStates : The new number of states.
//
// Returns:
//
// Note:       NOTE -- This method is not done and probably won't work yet.
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

void
DatabaseCorrelation::SetNumStates(int nStates)
{
    if(method == IndexForIndexCorrelation)
    {
        intVector newIndices;
        for(int i = 0; i < (int)databaseNames.size(); ++i)
        {
            for(int j = 0; j < nStates; ++j)
            {
                int state = (i < databaseNStates[i]) ? i :
                    (databaseNStates[i]-1);
                newIndices.push_back(state);
            }
        }
        indices = newIndices;
        numStates = nStates;
    }
    else if(method == StretchedIndexCorrelation)
    {
        intVector newIndices;
        int maxStates = (numStates > nStates) ? numStates : nStates;

        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            for(int j = 0; j < maxStates; ++j)
            {
                float t = float(j) / float(maxStates - 1);
                int state = int(t * databaseNStates[i] + 0.5);
                newIndices.push_back(state);
            }
        }
        indices = newIndices;
        numStates = maxStates;
    }
    else if(method == UserDefinedCorrelation)
    {
        intVector newIndices;
        int currentState = 0;
        int lastState = numStates - 1;
        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            for(int j = 0; j < nStates; ++j)
            {
                if(j < numStates)
                {
                    newIndices.push_back(indices[currentState++]);
                }
                else
                    newIndices.push_back(indices[lastState]);
            }

            lastState += numStates;
        }
    }
    //
    // Setting the number of time states for a time or cycle correlation database has
    // no effect because those correlations are controlled by the times and cycles
    // in the database that makes them up.
    //
}

void
DatabaseCorrelation::SetMethod(DatabaseCorrelation::CorrelationMethod method_)
{
    method = method_;
    Select(ID_method, (void *)&method);
}

void
DatabaseCorrelation::SetDatabaseNames(const stringVector &databaseNames_)
{
    databaseNames = databaseNames_;
    Select(ID_databaseNames, (void *)&databaseNames);
}

void
DatabaseCorrelation::SetDatabaseNStates(const intVector &databaseNStates_)
{
    databaseNStates = databaseNStates_;
    Select(ID_databaseNStates, (void *)&databaseNStates);
}

void
DatabaseCorrelation::SetDatabaseTimes(const doubleVector &databaseTimes_)
{
    databaseTimes = databaseTimes_;
    Select(ID_databaseTimes, (void *)&databaseTimes);
}

void
DatabaseCorrelation::SetDatabaseCycles(const intVector &databaseCycles_)
{
    databaseCycles = databaseCycles_;
    Select(ID_databaseCycles, (void *)&databaseCycles);
}

void
DatabaseCorrelation::SetIndices(const intVector &indices_)
{
    indices = indices_;
    Select(ID_indices, (void *)&indices);
}

void
DatabaseCorrelation::SetCondensedTimes(const doubleVector &condensedTimes_)
{
    condensedTimes = condensedTimes_;
    Select(ID_condensedTimes, (void *)&condensedTimes);
}

void
DatabaseCorrelation::SetCondensedCycles(const intVector &condensedCycles_)
{
    condensedCycles = condensedCycles_;
    Select(ID_condensedCycles, (void *)&condensedCycles);
}

///////////////////////////////////////////////////////////////////////////////
// Get property methods
///////////////////////////////////////////////////////////////////////////////

const std::string &
DatabaseCorrelation::GetName() const
{
    return name;
}

std::string &
DatabaseCorrelation::GetName()
{
    return name;
}

int
DatabaseCorrelation::GetNumStates() const
{
    return numStates;
}

DatabaseCorrelation::CorrelationMethod
DatabaseCorrelation::GetMethod() const
{
    return CorrelationMethod(method);
}

const stringVector &
DatabaseCorrelation::GetDatabaseNames() const
{
    return databaseNames;
}

stringVector &
DatabaseCorrelation::GetDatabaseNames()
{
    return databaseNames;
}

const intVector &
DatabaseCorrelation::GetDatabaseNStates() const
{
    return databaseNStates;
}

intVector &
DatabaseCorrelation::GetDatabaseNStates()
{
    return databaseNStates;
}

const doubleVector &
DatabaseCorrelation::GetDatabaseTimes() const
{
    return databaseTimes;
}

doubleVector &
DatabaseCorrelation::GetDatabaseTimes()
{
    return databaseTimes;
}

const intVector &
DatabaseCorrelation::GetDatabaseCycles() const
{
    return databaseCycles;
}

intVector &
DatabaseCorrelation::GetDatabaseCycles()
{
    return databaseCycles;
}

const intVector &
DatabaseCorrelation::GetIndices() const
{
    return indices;
}

intVector &
DatabaseCorrelation::GetIndices()
{
    return indices;
}

const doubleVector &
DatabaseCorrelation::GetCondensedTimes() const
{
    return condensedTimes;
}

doubleVector &
DatabaseCorrelation::GetCondensedTimes()
{
    return condensedTimes;
}

const intVector &
DatabaseCorrelation::GetCondensedCycles() const
{
    return condensedCycles;
}

intVector &
DatabaseCorrelation::GetCondensedCycles()
{
    return condensedCycles;
}

///////////////////////////////////////////////////////////////////////////////
// Select property methods
///////////////////////////////////////////////////////////////////////////////

void
DatabaseCorrelation::SelectName()
{
    Select(ID_name, (void *)&name);
}

void
DatabaseCorrelation::SelectDatabaseNames()
{
    Select(ID_databaseNames, (void *)&databaseNames);
}

void
DatabaseCorrelation::SelectDatabaseNStates()
{
    Select(ID_databaseNStates, (void *)&databaseNStates);
}

void
DatabaseCorrelation::SelectDatabaseTimes()
{
    Select(ID_databaseTimes, (void *)&databaseTimes);
}

void
DatabaseCorrelation::SelectDatabaseCycles()
{
    Select(ID_databaseCycles, (void *)&databaseCycles);
}

void
DatabaseCorrelation::SelectIndices()
{
    Select(ID_indices, (void *)&indices);
}

void
DatabaseCorrelation::SelectCondensedTimes()
{
    Select(ID_condensedTimes, (void *)&condensedTimes);
}

void
DatabaseCorrelation::SelectCondensedCycles()
{
    Select(ID_condensedCycles, (void *)&condensedCycles);
}

///////////////////////////////////////////////////////////////////////////////
// Keyframing methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: DatabaseCorrelation::GetFieldName
//
// Purpose:
//   This method returns the name of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

std::string
DatabaseCorrelation::GetFieldName(int index) const
{
    switch (index)
    {
    case ID_name:            return "name";
    case ID_numStates:       return "numStates";
    case ID_method:          return "method";
    case ID_databaseNames:   return "databaseNames";
    case ID_databaseNStates: return "databaseNStates";
    case ID_databaseTimes:   return "databaseTimes";
    case ID_databaseCycles:  return "databaseCycles";
    case ID_indices:         return "indices";
    case ID_condensedTimes:  return "condensedTimes";
    case ID_condensedCycles: return "condensedCycles";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetFieldType
//
// Purpose:
//   This method returns the type of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeGroup::FieldType
DatabaseCorrelation::GetFieldType(int index) const
{
    switch (index)
    {
    case ID_name:            return FieldType_string;
    case ID_numStates:       return FieldType_int;
    case ID_method:          return FieldType_enum;
    case ID_databaseNames:   return FieldType_stringVector;
    case ID_databaseNStates: return FieldType_intVector;
    case ID_databaseTimes:   return FieldType_doubleVector;
    case ID_databaseCycles:  return FieldType_intVector;
    case ID_indices:         return FieldType_intVector;
    case ID_condensedTimes:  return FieldType_doubleVector;
    case ID_condensedCycles: return FieldType_intVector;
    default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetFieldTypeName
//
// Purpose:
//   This method returns the name of a field type given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

std::string
DatabaseCorrelation::GetFieldTypeName(int index) const
{
    switch (index)
    {
    case ID_name:            return "string";
    case ID_numStates:       return "int";
    case ID_method:          return "enum";
    case ID_databaseNames:   return "stringVector";
    case ID_databaseNStates: return "intVector";
    case ID_databaseTimes:   return "doubleVector";
    case ID_databaseCycles:  return "intVector";
    case ID_indices:         return "intVector";
    case ID_condensedTimes:  return "doubleVector";
    case ID_condensedCycles: return "intVector";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: DatabaseCorrelation::FieldsEqual
//
// Purpose:
//   This method compares two fields and return true if they are equal.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    const DatabaseCorrelation &obj = *((const DatabaseCorrelation*)rhs);
    bool retval = false;
    switch (index_)
    {
    case ID_name:
        {  // new scope
        retval = (name == obj.name);
        }
        break;
    case ID_numStates:
        {  // new scope
        retval = (numStates == obj.numStates);
        }
        break;
    case ID_method:
        {  // new scope
        retval = (method == obj.method);
        }
        break;
    case ID_databaseNames:
        {  // new scope
        retval = (databaseNames == obj.databaseNames);
        }
        break;
    case ID_databaseNStates:
        {  // new scope
        retval = (databaseNStates == obj.databaseNStates);
        }
        break;
    case ID_databaseTimes:
        {  // new scope
        retval = (databaseTimes == obj.databaseTimes);
        }
        break;
    case ID_databaseCycles:
        {  // new scope
        retval = (databaseCycles == obj.databaseCycles);
        }
        break;
    case ID_indices:
        {  // new scope
        retval = (indices == obj.indices);
        }
        break;
    case ID_condensedTimes:
        {  // new scope
        retval = (condensedTimes == obj.condensedTimes);
        }
        break;
    case ID_condensedCycles:
        {  // new scope
        retval = (condensedCycles == obj.condensedCycles);
        }
        break;
    default: retval = false;
    }

    return retval;
}

///////////////////////////////////////////////////////////////////////////////
// User-defined methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: DatabaseCorrelation::GetCorrelatedTimeStates
//
// Purpose:
//   Gets the correlated time states for all databases in the correlation at
//   the specified time state.
//
// Arguments:
//   state : The state for which we want the correlated time states.
//   states : The return vector for the correlated time states.
//
// Returns:
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::GetCorrelatedTimeStates(int state, intVector &states) const
{
    bool retval = false;

    if(state >= 0 && state < numStates)
    {
        states.clear();
        int index = state;
        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            states.push_back(indices[index]);
            index += numStates;
        }
        retval = true;
    }

    return retval;
}

// ****************************************************************************
// Method: DatabaseCorrelation::AddDatabase
//
// Purpose:
//   Adds a new database to the correlation.
//
// Arguments:
//   database : The name of the database to add to the correlation.
//   nStates  : The number of states in the database.
//   times    : The times for the states in the database.
//   cycles   : The cycles for the states in the database.
//
// Returns:
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//   Brad Whitlock, Fri Apr 1 15:17:08 PST 2005
//   Fixed a rounding problem.
//
// ****************************************************************************

void
DatabaseCorrelation::AddDatabase(const std::string &database, int nStates,
    const doubleVector &times, const intVector &cycles)
{
    // If the database is already in the correlation, maybe we should
    // remove it and then add it again in case the length changed like
    // when we add time states to a file.
    if(UsesDatabase(database))
        return;

    //
    // Add the times and cycles for the new database to the correlation so
    // we can access them later and perhaps use them to correlate.
    //
    for(size_t i = 0; i < (size_t)nStates; ++i)
    {
        double t = ((i < times.size()) ? times[i] : 0.);
        databaseTimes.push_back(t);
        int c = ((i < cycles.size()) ? cycles[i] : 0);
        databaseCycles.push_back(c);
    }

    if(method == IndexForIndexCorrelation)
    {
        if(numStates >= nStates)
        {
            //
            // The number of states in the correlation is larger than
            // the number of states in the database so we can append
            // the database's states to the end of the indices and
            // repeat the last frames.
            //
            for(int i = 0; i < numStates; ++i)
            {
                int state = (i < nStates) ? i : (nStates - 1);
                indices.push_back(state);
            }
        }
        else
        {
            //
            // The number of states for the current database is larger
            // than the number of states in the correlation. The correlation
            // must be lengthened.
            //
            indices.clear();
            for(size_t i = 0; i < databaseNames.size(); ++i)
            {
                for(int j = 0; j < nStates; ++j)
                {
                    int state = (j < databaseNStates[i]) ? j :
                        (databaseNStates[i]-1);
                    indices.push_back(state);
                }
            }
            // Add the new database to the correlation.
            for(int i = 0; i < nStates; ++i)
                indices.push_back(i);

            numStates = nStates;
        }

        databaseNames.push_back(database);
        databaseNStates.push_back(nStates);
    }
    else if(method == StretchedIndexCorrelation)
    {
        databaseNames.push_back(database);
        databaseNStates.push_back(nStates);

        indices.clear();
        int maxStates = (numStates > nStates) ? numStates : nStates;
        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            for(int j = 0; j < maxStates; ++j)
            {
                float t = float(j) / float(maxStates - 1);
                int state = int(t * (databaseNStates[i] - 1) + 0.5);
                indices.push_back(state);
            }
        }

        numStates = maxStates;
    }
    else if(method == UserDefinedCorrelation)
    {
        if(numStates > nStates)
        {
            //
            // The database being added has fewer states so we need to
            // repeat the last states.
            //

            // We'll have to pass in the user-defined indices and append them to the indices vector
        }
        else
        {

        }
    }
    else if(method == TimeCorrelation)
    {
        databaseNames.push_back(database);
        databaseNStates.push_back(nStates);

        // Align time for all databases on the same time axis so we can count the
        // number of times and make that be the new number of states.
        std::map<double, intVector> timeAlignmentMap;
        int index = 0;
        for(size_t i = 0; i < databaseNames.size(); ++i)
            for(int j = 0; j < databaseNStates[i]; ++j, ++index)
                timeAlignmentMap[databaseTimes[index]].push_back((int)i);

        //
        // Set the condensed times vector
        //
        condensedTimes.clear();
        for(std::map<double,intVector>::const_iterator p = timeAlignmentMap.begin();
            p != timeAlignmentMap.end(); ++p)
        {
            condensedTimes.push_back(p->first);
        }

        // Now there is a map that has for each time in all of the databases
        // a list of the databases that contain that time.
        indices.clear();
        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            int state = 0;
            std::map<double, intVector>::const_iterator pos = timeAlignmentMap.begin();
            for(; pos != timeAlignmentMap.end(); ++pos)
            {
                // Look to see if the current database is in the list of databases
                // for the current time. If so, we need to increment the state after
                // we use it.
                intVector::const_iterator dbIndex =
                    std::find(pos->second.begin(), pos->second.end(), i);
                indices.push_back(state);
                if(dbIndex != pos->second.end() && state < databaseNStates[i] - 1)
                    ++state;
            }
        }

        numStates = timeAlignmentMap.size();
    }
    else if(method == CycleCorrelation)
    {
        databaseNames.push_back(database);
        databaseNStates.push_back(nStates);

        // Align cycle for all databases on the same time axis so we can count the
        // number of cycles and make that be the new number of states.
        std::map<int, intVector> cycleAlignmentMap;
        int index = 0;
        for(size_t i = 0; i < databaseNames.size(); ++i)
            for(int j = 0; j < databaseNStates[i]; ++j, ++index)
                cycleAlignmentMap[databaseCycles[index]].push_back((int)i);

        //
        // Set the condensed cycles vector
        //
        condensedCycles.clear();
        for(std::map<int,intVector>::const_iterator p = cycleAlignmentMap.begin();
            p != cycleAlignmentMap.end(); ++p)
        {
            condensedCycles.push_back(p->first);
        }

        // Now there is a map that has for each time in all of the databases
        // a list of the databases that contain that time.
        indices.clear();
        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            int state = 0;
            std::map<int, intVector>::const_iterator pos = cycleAlignmentMap.begin();
            for(; pos != cycleAlignmentMap.end(); ++pos)
            {
                // Look to see if the current database is in the list of databases
                // for the current time. If so, we need to increment the state after
                // we use it.
                intVector::const_iterator dbIndex =
                    std::find(pos->second.begin(), pos->second.end(), i);
                indices.push_back(state);
                if(dbIndex != pos->second.end() && state < databaseNStates[i] - 1)
                    ++state;
            }
        }

        numStates = cycleAlignmentMap.size();
    }
}

// ****************************************************************************
// Method: DatabaseCorrelation::UsesDatabase
//
// Purpose:
//   Returns whether or not a database is used in the correlation.
//
// Arguments:
//   database : The database we're checking for membership in the correlation.
//
// Returns:    True if database is used; false otherwise.
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

bool
DatabaseCorrelation::UsesDatabase(const std::string &database) const
{
    return std::find(databaseNames.begin(), databaseNames.end(), database) !=
           databaseNames.end();
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetNumDatabases
//
// Purpose:
//   Returns the number of databases used in the correlation.
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

int
DatabaseCorrelation::GetNumDatabases() const
{
    return databaseNames.size();
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetCorrelatedTimeState
//
// Purpose:
//   Gets the correlated time state for the specified database at the given state.
//
// Arguments:
//   db    : The database for which we want the correlated time.
//   state : The state for which we want the correlated time.
//
// Returns:    The correlated time state or -1 if no correlated time state
//             exists.
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

int
DatabaseCorrelation::GetCorrelatedTimeState(const std::string &db, int state) const
{
    int retval = -1;

    if(state >= 0 && state < numStates)
    {
        for(size_t i = 0; i < databaseNames.size(); ++i)
        {
            if(databaseNames[i] == db)
            {
                retval = indices[i * numStates + state];
                break;
            }
        }
    }

    return retval;
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetInverseCorrelatedTimeState
//
// Purpose:
//   Gets the state in the correlation where the database "db" has a database
//   state of "state".
//
// Arguments:
//   db    : The database for which we want the inverse correlated time.
//   state : The state for which we want the inverse correlated time.
//
// Returns:    The inverse correlated time state or -1 if no inverse
//             correlated time state exists.
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

int
DatabaseCorrelation::GetInverseCorrelatedTimeState(const std::string &db,
    int dbState) const
{
    int retval = -1;

    for(int i = 0; i < (int)databaseNames.size() && retval == -1; ++i)
    {
        if(databaseNames[i] == db)
        {
            int startIndex = i * numStates;
            for(int j = 0; j < numStates; ++j)
            {
                if(indices[startIndex + j] == dbState)
                {
                    retval = j;
                    break;
                }
            }
        }
    }

    return retval;
}

// ****************************************************************************
// Method: operator <<
//
// Purpose:
//   This is a print function for DatabaseCorrelation.
//
// Arguments:
//   os          : The stream to print on.
//   correlation : The correlation that we want to print.
//
// Returns:
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//   Brad Whitlock, Wed Apr 14 11:59:47 PDT 2004
//   Fixed for Windows compiler.
//
// ****************************************************************************

ostream &
operator << (ostream &os, const DatabaseCorrelation &correlation)
{
    os << "name = " << correlation.GetName().c_str() << endl;
    os << "numStates = " << correlation.GetNumStates() << endl;
    os << "method = " << DatabaseCorrelation::CorrelationMethod_ToString(correlation.GetMethod()).c_str() << endl;
    int index = 0;
    for(size_t i = 0; i < correlation.GetDatabaseNames().size(); ++i)
    {
        os << "database[" << i << "]=" << correlation.GetDatabaseNames()[i].c_str() << endl;
        os << "    numStates=" << correlation.GetDatabaseNStates()[i] << endl;
        os << "    times={";
        for(int j = 0; j < correlation.GetDatabaseNStates()[i]; ++j)
            os << correlation.GetDatabaseTimes()[index+j] << ", ";
        os << "}" << endl;

        os << "    cycles={";
        for(int j = 0; j < correlation.GetDatabaseNStates()[i]; ++j)
            os << correlation.GetDatabaseCycles()[index+j] << ", ";
        os << "}" << endl;

        index += correlation.GetDatabaseNStates()[i];

        os << "    indices={";
        for(int j = 0; j < correlation.GetNumStates(); ++j)
            os << correlation.GetIndices()[i*correlation.GetNumStates() + j] << ", ";
        os << "}" << endl;

    }

    const doubleVector &t = correlation.GetCondensedTimes();
    if(t.size() > 0)
    {
        os << "condensedTimes={";
        for(size_t j = 0; j < t.size(); ++j)
            os << t[j] << ", ";
        os << "}" << endl;
    }

    const intVector &c = correlation.GetCondensedCycles();
    if(c.size() > 0)
    {
        os << "condensedCycles={";
        for(size_t j = 0; j < c.size(); ++j)
            os << c[j] << ", ";
        os << "}" << endl;
    }

    return os;
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetCondensedCycleForState
//
// Purpose:
//   Returns the cycle for the specified state in a cycle correlation.
//
// Arguments:
//   state : The state for which we want the cycle.
//
// Returns:    The cycle at the specified state.
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

int
DatabaseCorrelation::GetCondensedCycleForState(int state) const
{
    int retval = 0;
    if(state >= 0 && (size_t)state < condensedCycles.size())
        retval = condensedCycles[state];

    return retval;
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetCondensedTimeForState
//
// Purpose:
//   Returns the time for the specified state in a time correlation.
//
// Arguments:
//   state : The state for which we want the time.
//
// Returns:    The time at the specified state.
//
// Note:
//
// Programmer: Brad Whitlock
// Creation:   Sat Jan 31 19:56:11 PST 2004
//
// Modifications:
//
// ****************************************************************************

double
DatabaseCorrelation::GetCondensedTimeForState(int state) const
{
    double retval = 0.;
    if(state >= 0 && (size_t)state < condensedTimes.size())
        retval = condensedTimes[state];

    return retval;
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetMethodName
//
// Purpose: Returns the correlation method name as a char*
//
// Programmer: Mark C. Miller
// Creation:   Tuesday, May 17, 2005
//
// ****************************************************************************

const char*
DatabaseCorrelation::GetMethodName() const
{
    return GetMethodNameFromMethod(GetMethod());
}

// ****************************************************************************
// Method: DatabaseCorrelation::GetMethodNameFromMethod
//
// Purpose: Returns the correlation method name as a char*
//
// Programmer: Mark C. Miller
// Creation:   Tuesday, May 17, 2005
//
// ****************************************************************************

const char*
DatabaseCorrelation::GetMethodNameFromMethod(int m)
{
    CorrelationMethod theMethod = (CorrelationMethod) m;
    switch(theMethod)
    {
        case IndexForIndexCorrelation:     return "Index";
        case StretchedIndexCorrelation:    return "StretchedIndex";
        case TimeCorrelation:              return "Time";
        case CycleCorrelation:             return "Cycle";
        case UserDefinedCorrelation:       return "User Defined";
    }
    return "Unknown";
}

